import os
import re
import sys
from PySide6.QtCore import (Slot,QRect)
from PySide6.QtWidgets import (
    QDialog,
    QDialogButtonBox,
    QTableWidget,
    QTableWidgetItem,
    QCheckBox,
    QPushButton, 
    QMessageBox,
    QLabel,
    QLineEdit
    )
from PySide6.QtUiTools import QUiLoader
import pandas as pd
from ModuleMaker import ModuleMaker
import codecs

class TodoWindow(QDialog):

    def __init__(self,data:pd.DataFrame) -> None:
        super().__init__()
        loader = QUiLoader()
        try:
            self.cur_path = sys._MEIPASS
        except:
            self.cur_path = os.path.dirname(os.path.realpath(__file__))
        self.TodoDialog:QDialog = loader.load(f"{self.cur_path}\\TodoWindow.ui", None)
        self.data:pd.DataFrame = data

        self.new_modules = []
        self.deleted_modules = []

        # init components
        self.buttonBox:QDialogButtonBox = self.TodoDialog.buttonBox
        self.mainTable:QTableWidget = self.TodoDialog.mainTable
        self.delModuleButton:QPushButton = self.TodoDialog.delModuleButton
        self.newModuleButton:QPushButton = self.TodoDialog.newModuleButton
        self.buttonBox.button(QDialogButtonBox.StandardButton.Save).setDisabled(True)

        # init handlers
        self.newModuleButton.clicked.connect(self.make_new_model)
        self.delModuleButton.clicked.connect(self.unbind_model)

        # init table data
        self.mainTable.setColumnWidth(0,400)
        self.refresh_table()


    def refresh_table(self):
        try:
            self.mainTable.clear()
            self.mainTable.setRowCount(0)
            for r,record in self.data.iterrows():
                self.mainTable.setRowCount(self.mainTable.rowCount()+1)
                self.mainTable.setItem(r,0,QTableWidgetItem(record["key"]))
                self.mainTable.setItem(r,1,QTableWidgetItem(record["module"]))           
                chb = QCheckBox(self.mainTable)
                chb.setProperty("key",record["key"])
                chb.setChecked(record["done"])
                chb.stateChanged.connect(self.item_state_changed)
                self.mainTable.setCellWidget(r,2,chb) 
        except: raise 

    def show(self)->int:
        result = self.TodoDialog.exec()
        if result==1:
            if self.deleted_modules.__len__()>0:
                for f_ in self.deleted_modules:
                    f:str = f_
                    os.rename(f,f.replace(".py","-deleted.py"))
        else:
            if self.new_modules.__len__()>0:
                for f in self.new_modules: os.remove(f)
        return result

    @Slot() # декоратор нужен для того, чтобы получить доступ к методу sender()
    def item_state_changed(self):
        chb:QCheckBox = self.sender()
        key:str=chb.property("key")
        checked = chb.isChecked()
        self.buttonBox.button(QDialogButtonBox.StandardButton.Save).setDisabled(False)
        self.data.loc[self.data["key"]==key,"done"]=checked
        
    def make_new_model(self):
        try:
            dialog=QDialog(self.TodoDialog)
            dialog.setWindowTitle("Новый модуль")
            dialog.setFixedSize(670,150)
            label1= QLabel(dialog)
            label2= QLabel(dialog)
            moduleName = QLineEdit(dialog)
            handlerName = QLineEdit(dialog)
            okButton = QPushButton(dialog)
            label1.setText("Модуль")
            label2.setText("Обработчик")
            okButton.setText("Ok")
            label1.setGeometry(QRect(10, 10, 51, 16))
            label2.setGeometry(QRect(10, 60, 81, 16))            
            moduleName.setGeometry(QRect( 10, 30, 651, 22))
            handlerName.setGeometry(QRect(10, 80, 651, 22))
            okButton.setGeometry(QRect(20,120,60,22))
            okButton.clicked.connect(dialog.accept)           
            if dialog.exec()==1:
                
                mName = moduleName.text() #.encode("utf-8").decode("utf-8")
                hName = handlerName.text()
                mm:list =re.findall("(?!([a-zA-Z_0-9]+)).",hName)
                if mm.__len__()>0 : raise Exception("Имя обработчика должно содержать a-zA-Z_0-9")
                if mName is None or mName.__len__()==0: raise Exception("Имя модуля должно содержать хоть один символ")
                hPath = f"{self.cur_path}\\handlers2\\{hName}.py"
                if os.path.isfile(hPath): raise Exception(f"Обработчик '{hPath}' уже существует.")
                mess = ModuleMaker.make_from_file(f"{self.cur_path}\\handlers2\\module_pattern.py",mName,hName,f"{self.cur_path}\\handlers2")
                print(mess)
                self.new_modules.append(f"{self.cur_path}\\handlers2\\{hName}.py")
                self.data.loc[len(self.data)] = [mName,hName,False]
                r = self.mainTable.rowCount()
                self.mainTable.setRowCount(r+1)
                self.mainTable.setItem(r,0,QTableWidgetItem(mName))
                self.mainTable.setItem(r,1,QTableWidgetItem(hName))           
                chb = QCheckBox(self.mainTable)
                chb.setProperty("key",mName)
                chb.setChecked(False)
                chb.stateChanged.connect(self.item_state_changed)
                self.mainTable.setCellWidget(r,2,chb)
                self.buttonBox.button(QDialogButtonBox.StandardButton.Save).setDisabled(False)
        except: raise
        
    def unbind_model(self):
        try:
            key = self.mainTable.selectedItems()[0].data(0)
            hName = self.mainTable.selectedItems()[1].data(0)
            result = QMessageBox.warning(self.TodoDialog, "Удаление модуля",
                f"Вы действительно хотите отвязать обработчик от модуля <b>'{key}'</b>?",
                QMessageBox.Ok | QMessageBox.Cancel,
                QMessageBox.Cancel)
            if result==QMessageBox.Ok:
                self.deleted_modules.append(f"{self.cur_path}\\handlers2\\{hName}.py")
                self.data.drop(self.data[self.data.key==key].index,inplace=True)
                self.refresh_table()
                self.buttonBox.button(QDialogButtonBox.StandardButton.Save).setDisabled(False)
                
        except: raise
    
    

    

